package ip

import (
	"encoding/json"
	"errors"
	"fmt"
	"go-fiber-ip2region/global"
	"go-fiber-ip2region/model/ip/response"
	"go-fiber-ip2region/storage"
	"io/ioutil"
	"net/http"

	"github.com/lionsoul2014/ip2region/binding/golang/ip2region"
)

type IpInfoService struct{}

func (i *IpInfoService) GetIpInfo(ip string) (ipInfo response.IpInfoReq, err error) {
	// 先查找缓存，缓存没有则调高德地图接口
	preStoreResult := storage.GetIpInfo(ip)

	if preStoreResult.City != "" || preStoreResult.ISP != "" {
		ipInfo = response.IpInfoReq{Country: preStoreResult.Country, Province: preStoreResult.Province, City: preStoreResult.City, ISP: preStoreResult.ISP}
		return ipInfo, err
	}

	// 缓存没有，请求amap获取
	var amapResult response.AmapIpInfoReq
	amapResult, err = getIpInfoFromAmap(ip)

	if amapResult.City != "" {
		ipInfo = response.IpInfoReq{Country: "中国", Province: amapResult.Province, City: amapResult.City}
		return ipInfo, err
	}

	// amap没有， 请求本地ip2region
	var localResult ip2region.IpInfo
	localResult, err = getIpInfoFromLocalDb(ip)
	if localResult.City == "" && preStoreResult.ISP == "" {
		err = errors.New("无法找到ip对应位置")
		return ipInfo, err
	}
	ipInfo = response.IpInfoReq{Country: localResult.Country, Province: localResult.Province, City: localResult.City, ISP: localResult.ISP}

	// 内存中存储
	storage.AddIpInfo(ip, ipInfo)

	return ipInfo, err
}

// 通过高德地图获取ip详情
func getIpInfoFromAmap(ip string) (ipInfo response.AmapIpInfoReq, err error) {
	url := "https://restapi.amap.com/v3/ip?" + "ip=" + ip + "&key=" + global.GLOBAL_CONFIG.AMAP_KEY

	var resp *http.Response
	resp, err = http.Get(url)

	if err != nil {
		fmt.Printf("get http err: %v\n", err)
	}

	defer resp.Body.Close()

	var ipInfoByte []byte
	ipInfoByte, err = ioutil.ReadAll(resp.Body)

	if err != nil {
		fmt.Printf("get http err: %v\n", err)
	}

	// json格式的 []byte 转 struct
	err = json.Unmarshal(ipInfoByte, &ipInfo)

	return ipInfo, err
}

// 本地数据库获取ip详情
func getIpInfoFromLocalDb(ip string) (ipInfo ip2region.IpInfo, err error) {
	region, err := ip2region.New("./ip2region.db")

	if err != nil {
		return ipInfo, err
	}
	defer region.Close()

	ipInfo, err = region.MemorySearch(ip)
	return ipInfo, err
}
